package com.moneycollect.example.classloader.loader;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.util.Base64;

/**
 * @author xuhuiqian
 * @since 2022/5/25 9:59
 */
public class LoaderUtils {
    // NOTE: please use config file for KEY and keep it safe, I use constant here for demo
    private final static String KEY = "gKvpH7oceZGR5pFEjDePLOXQTmvLdh2Xf+7ODVk6r8M=";
    private final static String IV = "Sov7U5/WBmSK5udUBaQGiw==";

    public static void encryptFile(String sourceFile, String targetFile) {
        try {
            byte[] fileContent = FileHelper.readFileToBytes(sourceFile);
            byte[] encryptFileContent = AESHelper.AESEncrypt(fileContent, KEY, IV);
            FileHelper.saveFile(encryptFileContent, targetFile);
        } catch (Exception e) {
            throw new RuntimeException("encrypt file fail: " + e.getMessage(), e);
        }
    }

    public static void encryptFile(byte[] sourceFileBytes, String targetFile) {
        try {
            byte[] encryptFileContent = AESHelper.AESEncrypt(sourceFileBytes, KEY, IV);
            FileHelper.saveFile(encryptFileContent, targetFile);
        } catch (Exception e) {
            throw new RuntimeException("encrypt file fail: " + e.getMessage(), e);
        }
    }

    public static byte[] decryptFile(String sourceFile) {
        try {
            byte[] encryptFileContent = FileHelper.readFileToBytes(sourceFile);
            return AESHelper.AESDecrypt(encryptFileContent, KEY, IV);
        } catch (IOException e) {
            throw new RuntimeException("decrypt file fail: " + e.getMessage(), e);
        }
    }

    public static byte[] decryptFile(byte[] encryptFileBytes) {
        try {
            return AESHelper.AESDecrypt(encryptFileBytes, KEY, IV);
        } catch (Exception e) {
            throw new RuntimeException("decrypt file fail: " + e.getMessage(), e);
        }
    }

    private static class AESHelper {
        /* 暂时不用的代码
        public static String[] GetFixedKeys() {
            return new String[] {"ll7uz0DREVGBA9IJxmnwoEsJoQtgpGPqXQOzmYgaS6o=", "yuntM97GbF5ISjSsx0qKqA=="};
        }

        public static String[] GetKeys() {
            try {
                var keyGen = KeyGenerator.getInstance("AES");
                keyGen.init(256);
                var secretKey = keyGen.generateKey();
                var byteKey = secretKey.getEncoded();
                var key = Base64.getEncoder().encodeToString(byteKey);
                var iv = Base64.getEncoder().encodeToString(SecureRandom.getInstanceStrong().generateSeed(16));
                return new String[]{key, iv};
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        */

        public static byte[] AESEncrypt(byte[] inputBytes, String key, String iv) {
            try {
                var cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, getKeySpec(key), getIvSpec(iv));
                return cipher.doFinal(inputBytes);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        public static byte[] AESDecrypt(byte[] inputBytes, String key, String iv) {
            try {
                var cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.DECRYPT_MODE, getKeySpec(key), getIvSpec(iv));
                return cipher.doFinal(inputBytes);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        private static SecretKeySpec getKeySpec(String key) {
            var bytesKey = Base64.getDecoder().decode(key);
            return new SecretKeySpec(bytesKey, "AES");
        }

        private static IvParameterSpec getIvSpec(String iv) {
            var bytesIV = Base64.getDecoder().decode(iv);
            return new IvParameterSpec(bytesIV);
        }


    }
}
